import java.util.ArrayList;
import java.util.Collections;
import java.util.Timer;
import java.util.TimerTask;

public class TitleBarInfo
{
	private class InfoMessage
	{
		private String InfoText;
		private int InfoTicksRemaining;
		private int ActivationTicksRemaining;
		private int ShowPendingTick;
		private boolean ShowWaitCursorUntilRemoved;

		public InfoMessage(String InfoText, boolean AutoRemove, boolean DelayedActivation, boolean ShowPending, boolean ShowWaitCursorUntilRemoved)
		{
			if (InfoText.length() < 1)
			{
				System.out.println("error in TitleBarInfo.InfoElement(): passed value not useful!");
			}
			if (InfoText.length() > 1000)
			{
				InfoText = InfoText.substring(0, 1000) + "[...]";
				System.out.println("error in TitleBarInfo.InfoElement(): passed value not useful!");
			}

			this.InfoText = InfoText;

			if (AutoRemove)
				this.InfoTicksRemaining = 3 * 10; // 3 seconds
			else
				this.InfoTicksRemaining = Integer.MAX_VALUE;

			if (DelayedActivation)
				this.ActivationTicksRemaining = 1 * 10; // 1 second
			else
				this.ActivationTicksRemaining = 0;

			if (ShowPending)
				this.ShowPendingTick = 0;
			else
				this.ShowPendingTick = -1;

			this.ShowWaitCursorUntilRemoved = ShowWaitCursorUntilRemoved;
		}
	}

	private ArrayList<InfoMessage> InfoMessages;

	private Timer TickTimer = null;
	private TimerTask TickTimerTask;

	private MainWindow MainWindow;
	private String MainWindowBaseTitle;

	private int ShowWaitCursorCounter = 0;

	// IMPORTANT: assume public methods get called concurrently from different
	// threads, especially as a result of the user doing mouse/keyboard input AND
	// from the Java redraw thread - DO NOT USE ANY LOCKING (MUTEX ETC.)!
	// System has deadlocked in tests when having used a ReentrantLock.

	public TitleBarInfo(MainWindow MainWindow, String MainWindowBaseTitle)
	{
		InfoMessages = new ArrayList<InfoMessage>();

		this.MainWindow = MainWindow;
		this.MainWindowBaseTitle = MainWindowBaseTitle;

		TickTimerTask = new TimerTask()
		{
			@Override
			public void run()
			{
				TitleBarInfoTick();
			}
		};

		TickTimer = new Timer();
		TickTimer.schedule(TickTimerTask, 0, 100); // less than 10 times per second was too sluggish (confusing)
	}

	public void AddInfoText(String InfoText, boolean AutoRemove, boolean DelayedActivation, boolean ShowPending, boolean ShowWaitCursorUntilRemoved)
	{
		// check if already existing (allowed once only)
		for (int i = 0; i < InfoMessages.size(); i++)
		{
			if (InfoMessages.get(i).InfoText.equals(InfoText)) // do not compare StayUntilRemoved, not useful
			{
				return;
			}
		}

		// add
		InfoMessage NewInfoElement = new InfoMessage(InfoText, AutoRemove, DelayedActivation, ShowPending, ShowWaitCursorUntilRemoved);
		for (int i = 0; i < InfoMessages.size(); i++)
		{
			// try to re-use an obsolete (removed) message location; so we don't need to
			// remove elements from ArrayList<>, which has caused problems when
			// an other thread has removed messages at the same time

			if (InfoMessages.get(i).InfoText.length() == 0)
			{
				InfoMessages.set(i, NewInfoElement);
				return;
			}
		}
		InfoMessages.add(NewInfoElement);
		return;
	}

	public void RemoveInfoText(String InfoText)
	{
		for (int i = 0; i < InfoMessages.size(); i++)
		{
			if (InfoMessages.get(i).InfoText.length() > 0)
			{
				String InfoTextWithoutPending = InfoMessages.get(i).InfoText;

				if (InfoTextWithoutPending.contains("☺")) // progress shown?
					InfoTextWithoutPending = InfoTextWithoutPending.substring(0, InfoTextWithoutPending.length() - (1 + 3));

				if (InfoTextWithoutPending.equals(InfoText))
				{
					if (InfoMessages.get(i).ShowWaitCursorUntilRemoved)
					{
						ShowDefaultCursor(); // not clear what to do if there would be SEVERAL show-wait-cursor elements, just don't add several ones (would not make sense anyway)
					}

					InfoMessages.get(i).InfoText = "";
				}
			}
		}
	}

	public void RemoveInfoTextContaining(String InfoTextPart)
	{
		for (int i = 0; i < InfoMessages.size(); i++)
		{
			if (InfoMessages.get(i).InfoText.length() > 0)
			{
				if (InfoMessages.get(i).InfoText.toLowerCase().contains(InfoTextPart.toLowerCase()))
				{
					if (InfoMessages.get(i).ShowWaitCursorUntilRemoved)
					{
						ShowDefaultCursor(); // not clear what to do if there would be SEVERAL show-wait-cursor elements, just don't add several ones (would not make sense anyway)
					}

					InfoMessages.get(i).InfoText = "";
				}
			}
		}
	}

	private void ShowDefaultCursor()
	{
		if (ShowWaitCursorCounter >= 1)
			ShowWaitCursorCounter--;
		// else
		// System.out.println("warning in TitleBarInfo.ShowDefaultCursor(): ShowWaitCursorCounter value not useful - more often wait cursor reset than set!");
		if (ShowWaitCursorCounter == 0)
		{
			CursorManager.SetWaitCursorEnabled(false);
		}
	}

	private void ShowWaitCursor()
	{
		ShowWaitCursorCounter++;
		if (ShowWaitCursorCounter >= 1)
		{
			CursorManager.SetWaitCursorEnabled(true);
		}
	}

	private void TitleBarInfoTick()
	{
		for (int i = 0; i < InfoMessages.size(); i++)
		{
			if (InfoMessages.get(i).InfoText.length() > 0)
			{
				if (InfoMessages.get(i).ActivationTicksRemaining >= 1)
				{
					// WAIT for displaying message...

					InfoMessages.get(i).ActivationTicksRemaining--;
					if (InfoMessages.get(i).ActivationTicksRemaining == 0)
					{
						if (InfoMessages.get(i).ShowWaitCursorUntilRemoved)
						{
							ShowWaitCursor(); // checks if already set to save CPU time
						}
					}
				}
				else if (InfoMessages.get(i).InfoTicksRemaining <= 0)
				{
					// message is being displayed and now to be removed as displaying time span over

					if (InfoMessages.get(i).ShowWaitCursorUntilRemoved)
					{
						ShowDefaultCursor(); // not clear what to do if there would be SEVERAL show-wait-cursor elements, just don't add several ones (would not make sense anyway)
					}
					InfoMessages.get(i).InfoText = "";
				}
				else
				{
					// message is being displayed, update it if necessary

					if (InfoMessages.get(i).InfoTicksRemaining != Integer.MAX_VALUE) // ELSE if!
						InfoMessages.get(i).InfoTicksRemaining--;

					if (InfoMessages.get(i).ShowPendingTick >= 0) // enabled?
						InfoMessages.get(i).ShowPendingTick++;
					if (InfoMessages.get(i).ShowPendingTick >= 2 * 10)
						InfoMessages.get(i).ShowPendingTick = 0; // cycle
				}
			}
		}

		UpdateTitleBarInfo();
	}

	public void UpdateTitleBarInfo()
	{
		ArrayList<String> TitleBarInfoMessages = new ArrayList<String>();

		for (int i = 0; i < InfoMessages.size(); i++)
		{
			if (InfoMessages.get(i).InfoText.length() > 0)
			{
				if (InfoMessages.get(i).ActivationTicksRemaining <= 0)
				{
					String TitleBarInfoMessage = InfoMessages.get(i).InfoText;

					if (InfoMessages.get(i).ShowPendingTick >= 0)
					{
						switch ((int) (InfoMessages.get(i).ShowPendingTick / 10))
						{
						/*
						case 0:
							TitleBarInfoMessage += " ☻☺☺";
							break;
						case 1:
							TitleBarInfoMessage += " ☺☻☺";
							break;
						case 2:
							TitleBarInfoMessage += " ☺☺☻";
							break;
						}
						*/
						case 0:
							TitleBarInfoMessage += " ☻☺";
							break;
						case 1:
							TitleBarInfoMessage += " ☺☻";
							break;
						}
					}

					TitleBarInfoMessages.add(TitleBarInfoMessage);
				}
			}
		}

		Collections.sort(TitleBarInfoMessages); // https://www.javatpoint.com/how-to-sort-arraylist-in-java

		String TitleBarInfoString = "";

		for (int m = 0; m < TitleBarInfoMessages.size(); m++)
			TitleBarInfoString += " ~ " + TitleBarInfoMessages.get(m);

		if (!(MainWindow.getTitle().equals(MainWindowBaseTitle + TitleBarInfoString)))
			MainWindow.setTitle(MainWindowBaseTitle + TitleBarInfoString);
	}
}
